import time

import smbus


class MS8607:
    def __init__(self, rw_handler=None):
        self.__rw_handler = rw_handler
        self.__tp_add = 0x76
        self.__rh_add = 0x40
        self.cali_datas = [0, 0, 0, 0, 0, 0]
        self.init_sensor()

    def __on_rw_handler(self, dev_add, rw_flag, cmd, vals=None, size=0):
        if self.__rw_handler is None:  # 没有指定I2C读写回调函数按树莓派进行处理
            # 创建I2C操作类
            iic = smbus.SMBus(1)
            if rw_flag == 0:
                rst = iic.read_i2c_block_data(dev_add, cmd, size)
            else:
                if vals is None:
                    rst = iic.write_byte(dev_add, cmd)
                else:
                    rst = iic.write_i2c_block_data(dev_add, cmd, bytes(vals))
        else:
            rst = self.__rw_handler(dev_add, rw_flag, cmd, vals, size)
        return rst

    def init_sensor(self):
        self.__on_rw_handler(self.__tp_add, 1, 0x1E)
        self.cali_datas.clear()
        for cmd in range(0xA2, 0xAE, 2):
            rts = self.__on_rw_handler(dev_add=self.__tp_add, rw_flag=0, cmd=cmd, size=2)
            self.cali_datas.append(rts[0] << 8 | rts[1])
        print(self.cali_datas)
        self.__on_rw_handler(self.__rh_add, 1, 0xFE)

    def read_t(self):
        try:
            self.__on_rw_handler(self.__tp_add, 1, 0x5A)
            time.sleep(0.03)
            word = self.__on_rw_handler(dev_add=self.__tp_add,
                                        rw_flag=0,
                                        cmd=0x00,
                                        size=3)
            D2 = word[0] << 16 | word[1] << 8 | word[2]
        except:
            return None, None, None

        dT = D2 - self.cali_datas[4] * 2 ** 8
        TEMP = 2000 + dT * self.cali_datas[5] / 2 ** 23
        T = TEMP / 100.0
        return T, TEMP, dT

    def read_tp(self):
        T, TEMP, dT = self.read_t()
        if T is None or TEMP is None or dT is None:
            return None, None

        try:
            self.__on_rw_handler(self.__tp_add, 1, 0x4A)
            time.sleep(0.03)
            word = self.__on_rw_handler(dev_add=self.__tp_add,
                                        rw_flag=0,
                                        cmd=0x00,
                                        size=3)
            D1 = word[0] << 16 | word[1] << 8 | word[2]
        except:
            return T, None

        OFF = self.cali_datas[1] * 2 ** 17 + self.cali_datas[3] * dT / 2 ** 6
        SENS = self.cali_datas[0] * 2 ** 16 + self.cali_datas[2] * dT / 2 ** 7
        if TEMP < 2000:
            T2 = 3*dT**2/2**33
            OFF2 = 61*(TEMP - 2000)**2/2**4
            SENS2 = 29*(TEMP - 2000)**2/2**4
            if TEMP < -1500:
                OFF2 = OFF2 + 17*(TEMP + 1500)**2
                SENS2 = SENS2 + 9*(TEMP + 1500)**2
        else:
            T2 = 5*dT**2/2**38
            OFF2 = 0
            SENS2 = 0

        OFF = OFF - OFF2
        SENS = SENS - SENS2

        P = (D1*SENS/2**21 - OFF)/2**15/100.0

        return T, P

    def read_rh(self, T=20):
        try:
            word = self.__on_rw_handler(dev_add=self.__rh_add,
                                        rw_flag=0,
                                        cmd=0xE5,
                                        size=2)
            D3 = word[0] << 8 | word[1]
        except:
            return None

        RH = -6.0 + 125.0*D3/2**16
        if T is not None:
            RH = RH + 0.18 * (T - 20.0)
        return RH

    def read_tph(self):
        T, P = self.read_tp()
        H = self.read_rh(T)
        return T, P, H


if __name__ == '__main__':
    dd = MS8607()
    rts = dd.read_tph()
    print(rts)
